Jx.declare('Jx.lib.String', {

	$singleton: true,

	_wordRe: /^[a-z]|[^a-z][a-z]/ig,

	_leftTrimRe: /^[\s\t\r\n ]+/,

	_rightTrimRe: /[\s\t\r\n ]+$/,

	_headerPairsRe: /^([^\r\n\:]+)\:(.+)$/,

	_cEscapeRe: /[^\u0020-\u0021\u0023-\u0026\u0028-\u007e]/g,

	_escapables: {

		'"': '"',

		"'": "'",

		'/': '/',

		'\\': '\\',

		'\u0008': 'b',

		'\u000c': 'f',

		'\r': 'r',

		'\n': 'n',

		'\u0009': 't'

	},

	onWordReplaceCallback: function(m){

		var l = m.length,

			at = l - 1;

		return m.substring(0, at) + m.charAt(at).toUpperCase();

	},

	ucwords: function(str){

		return str.replace(this._wordRe, this.onWordReplaceCallback);

	},

	repeat: function(str, n){

		for(var rep = ''; n--;){

			rep+=str;

		}

		return rep;

	},

	trim: function(str){

		var left = arguments[1],

			l = left === true,

			r = left === false;

		if (l || !r){

			str = str.replace(this._leftTrimRe,'');

		}

		if (r || !l){

			str = str.replace(this._rightTrimRe,'');

		}

		return str;

	},

	pad: function(str, len, chr, right){

		var deficit, pad, c, pl;

		if (Jx.isScalar(str) && Jx.isNumber(len, 0) && Jx.isString(chr, true)){

			deficit = len - (str = String(str)).length;

			if (deficit > 0){

				pad = '';

				pl = chr.length;

				c = 0;

				while(deficit--){

					pad += chr.charAt(

						c = (c + 1) % pl

					);

				}

				str = right === true ?

					str + pad

					:

					pad + str;

			}

		}

		return str;

	},

	escape: function(str){

		var my = this,

			esc = this._escapables;

		return Jx.isString(str) ?

			str.replace(this._cEscapeRe, function(m){

				var code = m.charCodeAt(0);

				return '\\' + (

					code >= 3 && code <= 126 ?

						(m in esc ? esc[m] : m)

						:

						'u' + my.pad( code.toString(16), 4, '0' )

				);

			})

			:

			'';

	},

	urlEncode: typeof encodeURIComponent == 'undefined' ?

		function(o){ return Jx.isString(o) ? escape(o) : ''; }

		:

		function(o){ return Jx.isString(o) ? encodeURIComponent(o) : ''; },

	urlDecode: typeof decodeURIComponent == 'undefined' ?

		function(o){ return Jx.isString(o) ? unescape(o) : ''; }

		:

		function(o){ return Jx.isString(o) ? decodeURIComponent(o) : ''; },

	parseHeaders: function(headerString){

		var headers = {},

			pairRe = this._headerPairsRe,

			index,

			pairs, pair, name, value, current;

		if (Jx.isString(headerString, true) &&

			(pairs = headerString.split('\n')).length

		){

			for(var c=0,l=pairs.length; c<l; c++){

				pair = this.trim(pairs[c]);

				index = pair.indexOf(':')

				if (index != -1){

					name = this.trim(pair.substring(0, index));

					value = this.trim(pair.substring(index+1, pair.length));

					current = headers.hasOwnProperty(name) ?

						headers[name]

						:

						(headers[name] = []);

					current.push(value);

				} else if (pair && current){

					current[current.length - 1] += ' '+pair;

				}

			}

		}

		return headers;

	}

});
